﻿using Com.Lancetinc.Evs.Cameras;
using Com.Lancetinc.Evs.Controls;
using Com.Lancetinc.Evs.Helpers;
using Com.Lancetinc.Evs.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using NLog;

namespace Com.Lancetinc.Evs.Windows
{
    /// <summary>
    /// 视频设置/预览
    /// </summary>
    public partial class VideoSettingWindow
    {
        private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

        private readonly Dictionary<CameraProp, CameraPropBaseUserControl> propCtrls;
        private readonly CameraProp[] videoParamProps;
        private readonly CameraProp[] whiteBalanceProps;

        public VideoSettingWindow()
        {
            InitializeComponent();

            ThemeHelper.ChangeThemeToDark(this);

            this.propCtrls = new Dictionary<CameraProp, CameraPropBaseUserControl>();
            // 视频参数
            videoParamProps = CameraProps.ALL.Where(x => x.Category == CameraPropCategory.ProcAmp || x.Category == CameraPropCategory.Control).ToArray();
            InitializePropCtrls(videoParamProps, PanelVideoParamProps.Children);

            // 白平衡参数
            whiteBalanceProps = CameraProps.ALL.Where(x => x.Category == CameraPropCategory.WhiteBalance).ToArray();
            InitializePropCtrls(whiteBalanceProps, PanelWhiteBalanceProps.Children);
        }

        private void InitializePropCtrls(IEnumerable<CameraProp> cameraProps, UIElementCollection children)
        {
            foreach (var prop in cameraProps)
            {
                var ctrl = CreateCameraPropControl(prop);
                ctrl.Height = 40;
                ctrl.CameraProp = prop;
                ctrl.CameraPropChange += Ctrl_CameraPropChange;
                children.Add(ctrl);
                this.propCtrls[prop] = ctrl;
            }
        }

        private CameraPropBaseUserControl CreateCameraPropControl(CameraProp prop)
        {
            if (prop.Category == CameraPropCategory.ProcAmp)
            {
                if (prop.PropId == (int)CameraPropProcAmp.PowerLine)
                {
                    return new CameraPropPowerLineSettingUserControl();
                }
            }
            else if (prop.Category == CameraPropCategory.Control)
            {
                if (prop.PropId == (int)CameraPropControl.LowlightCompensation)
                {
                    return new CameraPropLowlightCompensationSettingUserControl();
                }
            }
            return new CameraPropSettingUserControl();
        }

        private void Ctrl_CameraPropChange(object sender, CameraPropChangeEventArgs e)
        {
            try
            {
                string typeCode = ActiveApp.Instance.GetEndoscopicTypeCode();
                if (typeCode == null)
                {
                    MessageHelper.ShowWarningByMsgId("CannotSetWhiteBalanceParameterBecauseofEndoscopeNotConnected");
                    this.Close();
                    return;
                }

                WpfHelper.ExecLaterEx("PropChange_" + e.PropertyName, () =>
                {
                    int deviceIndex = CameraLib.FindVideoDeviceIndex(typeCode);

                    CameraProp newProp = new CameraProp(e.Prop);
                    if (e.PropertyName.EndsWith("Value"))
                    {
                        newProp.Value = (int)e.NewValue;
                    }
                    else if (e.PropertyName.EndsWith("Auto"))
                    {
                        newProp.AutoFlag = (bool)e.NewValue ? CameraPropAutoFlag.Auto : CameraPropAutoFlag.Manual;
                    }
                    SavePropThenUpdateUI(deviceIndex, newProp, e.Prop);
                }, 300);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                propCtrls[e.Prop].ResetChange(e);
                MessageHelper.ShowWarning(ex.Message);
            }
        }

        private void SavePropThenUpdateUI(int deviceIndex, CameraProp newProp, CameraProp rawProp)
        {
            if (newProp.Category == CameraPropCategory.WhiteBalance)
            {
                WhiteBalanceHelper.SaveProp(deviceIndex, newProp, whiteBalanceProps);
                rawProp.Value = newProp.Value;
            }
            else
            {
                Logger.Info($"save prop to {deviceIndex}:" + newProp.ToShortString());
                CameraLib.SaveProp(deviceIndex, newProp);
                CameraLib.LoadPropValue(deviceIndex, rawProp);
            }
            propCtrls[rawProp].CameraProp = rawProp;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                string typeCode = ActiveApp.Instance.GetEndoscopicTypeCode();
                if (typeCode == null)
                {
                    MessageHelper.ShowWarningByMsgId("CannotSetWhiteBalanceParameterBecauseofEndoscopeNotConnected");
                    WpfHelper.ExecLater(Close);
                    return;
                }

                // 内窥镜配置
                var config = AppConfigHelper.GetEndoscopicConfigByHcSerialNo(ActiveApp.Instance.Instrument.HcSerialNo);
                if (config == null)
                {
                    // 请确认上位机软件是否为最新版本
                    MessageHelper.ShowWarningByMsgId("Run.CannotFoundConfigBySerialNo");
                    WpfHelper.ExecLater(Close);
                    return;
                }

                int deviceIndex = CameraLib.FindVideoDeviceIndex(typeCode);
                var deviceName = CameraLib.GetDeviceName(deviceIndex);

                var videoInfo = new VideoDeviceInfo()
                {
                    DeviceName = deviceName,
                    VideoWidth = config.HorizontalResolution,
                    VideoHeight = config.VerticalResolution,
                    VideoFormat = config.VideoFormat
                };

                // 视频预览
                VideoPreviewCtrl.Play(videoInfo);

                // 白平衡参数
                if (WhiteBalanceHelper.InitializeProps(deviceIndex, whiteBalanceProps))
                {
                    GbWhiteBalanceProps.IsEnabled = true;
                }
                else
                {
                    WhiteBalanceCannotConfigError.Visibility = Visibility.Visible;
                }

                // 视频参数（右侧部分）
                CameraLib.InitializeProps(deviceIndex, videoParamProps);
                foreach (CameraProp prop in propCtrls.Keys)
                {
                    propCtrls[prop].CameraProp = prop;
                }
                GbVideoParamProps.IsEnabled = true;

                ActiveApp.Instance.InstManager.StateChanged += InstManager_StateChanged;
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                MessageHelper.ShowError(ex.Message);
                WpfHelper.ExecLater(Close);
            }
        }

        private void InstManager_StateChanged(object sender, Communications.InstrumentInfoChangedEventArgs e)
        {
            if (!e.Instrument.EndoscopicConnected || !e.Instrument.InstrumentConnected)
            {
                ActiveApp.Instance.InstManager.StateChanged -= InstManager_StateChanged;
                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
                {
                    MessageHelper.ShowWarningByMsgId("CannotSetWhiteBalanceParameterBecauseofEndoscopeNotConnected");
                    this.Close();
                }));
            }
        }

        private void Window_Unloaded(object sender, RoutedEventArgs e)
        {
            ActiveApp.Instance.InstManager.StateChanged -= InstManager_StateChanged;
            HCameraLib.hFreeVideoDevice();
        }

        private void BtnWhiteBalanceReset_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string typeCode = ActiveApp.Instance.GetEndoscopicTypeCode();
                if (typeCode == null)
                {
                    MessageHelper.ShowWarningByMsgId("CannotSetWhiteBalanceParameterBecauseofEndoscopeNotConnected");
                    this.Close();
                    return;
                }
                int deviceIndex = CameraLib.FindVideoDeviceIndex(typeCode);
                foreach (CameraProp prop in whiteBalanceProps)
                {
                    // 恢复默认值
                    var newProp = new CameraProp(prop)
                    {
                        Value = prop.DefaultValue
                    };
                    SavePropThenUpdateUI(deviceIndex, newProp, prop);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                MessageHelper.ShowError(ex.Message);
            }
        }

        private void BtnVideoParamReset_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string typeCode = ActiveApp.Instance.GetEndoscopicTypeCode();
                if (typeCode == null)
                {
                    MessageHelper.ShowWarningByMsgId("CannotSetWhiteBalanceParameterBecauseofEndoscopeNotConnected");
                    this.Close();
                    return;
                }
                int deviceIndex = CameraLib.FindVideoDeviceIndex(typeCode);
                foreach (CameraProp prop in videoParamProps)
                {
                    // 恢复默认值
                    var newProp = new CameraProp(prop)
                    {
                        Value = prop.DefaultValue
                    };
                    SavePropThenUpdateUI(deviceIndex, newProp, prop);

                    // 提供自动和手动，且非自动的场合
                    if (prop.ModifyFlag == CameraPropModifyFlag.AutoAndManual && prop.AutoFlag != CameraPropAutoFlag.Auto)
                    {
                        newProp = new CameraProp(prop)
                        {
                            AutoFlag = CameraPropAutoFlag.Auto
                        };
                        SavePropThenUpdateUI(deviceIndex, newProp, prop);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                MessageHelper.ShowError(ex.Message);
            }
        }
    }
}
